package com.brillilab.common.utils;

import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;

public class DateUtil {

    public static final String DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
    public static final String DATE_FORMAT = "yyyy-MM-dd";
    public static final String DATE_MONTH_FORMAT = "yyyy-MM";
    public static final String DATE_HOUR_FORMAT = "yyyy-MM-dd HH";

    /**
     * 当前时间所在周开始日期
     */
    public static Date getBeginDayOfWeek() {
        return getWeekDate(true, new Date());
    }

    /**
     * 当前时间所在周结束日期
     */
    public static Date getEndDayOfWeek() {
        return getWeekDate(false, new Date());
    }

    /**
     * 时间所在周开始日期
     */
    public static Date getBeginDayOfWeek(Date date) {
        return getWeekDate(true, date);
    }

    /**
     * 时间所在周结束日期
     */
    public static Date getEndDayOfWeek(Date date) {
        return getWeekDate(false, date);
    }

    /**
     * 获取下一天的毫秒值
     *
     * @return
     */
    public static Long getNextTime() {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.add(Calendar.DAY_OF_MONTH, 1);
        return calendar.getTimeInMillis();
    }

    /**
     * 获取当前时间毫秒值
     *
     * @return
     */
    public static Long getCurrentTime() {
        return Calendar.getInstance().getTimeInMillis();
    }

    private static Date getWeekDate(boolean isBeginDay, Date date) {

        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        int d = 0;
        if (cal.get(Calendar.DAY_OF_WEEK) == 1) {
            d = -6;
        } else {
            d = 2 - cal.get(Calendar.DAY_OF_WEEK);
        }
        if (isBeginDay) {
            // 所在周开始日期
            cal.add(Calendar.DAY_OF_WEEK, d);
            //时分秒毫秒清零
            cal.set(Calendar.HOUR_OF_DAY, 0);
            cal.set(Calendar.MINUTE, 0);
            cal.set(Calendar.SECOND, 0);
            cal.set(Calendar.MILLISECOND, 0);
        } else {
            // 所在周结束日期
            cal.add(Calendar.DAY_OF_WEEK, d);
            cal.add(Calendar.DAY_OF_WEEK, 6);
            cal.set(Calendar.HOUR_OF_DAY, 23);
            cal.set(Calendar.MINUTE, 59);
            cal.set(Calendar.SECOND, 59);
            cal.set(Calendar.MILLISECOND, 0);
        }

        return cal.getTime();

    }

    /**
     * 获取近7天时间列表
     * getNextDay
     *
     * @param dateFormat
     * @return
     */
    public static List<String> getBeforeSevenDay(String dateFormat) {
        List<String> list = new ArrayList<String>();
        SimpleDateFormat sdf = new SimpleDateFormat(dateFormat);
        Calendar c = null;
        for (int i = 0; i < 7; i++) {
            c = Calendar.getInstance();
            c.add(Calendar.DAY_OF_MONTH, -i - 1);
            list.add(sdf.format(c.getTime()));

        }
        return list;
    }

    /**
     * 获取两个日期之间的时间列表
     *
     * @param startDay
     * @param endDay
     * @return
     */
    public static List<String> getBetweenDay(Date startDay, Date endDay) {
        List<String> list = new ArrayList<>();
        SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT);
        Calendar c = null;
        int betweenDate = getDiffDays(startDay, endDay);
        for (int i = 0; i <= betweenDate; i++) {
            c = Calendar.getInstance();
            c.setTime(startDay);
            c.add(Calendar.DAY_OF_MONTH, i);
            list.add(sdf.format(c.getTime()));
        }
        return list;
    }

    /**
     * 获取两个月份之间的时间列表
     *
     * @param startMonth
     * @param endMonth
     * @return
     */
    public static List<String> getBetweenMonth(Date startMonth, Date endMonth) {
        List<String> list = new ArrayList<>();
        SimpleDateFormat sdf = new SimpleDateFormat(DATE_MONTH_FORMAT);
        Calendar c = null;
        int betweenMonth = getDiffMonths(startMonth, endMonth);
        for (int i = 0; i <= betweenMonth; i++) {
            c = Calendar.getInstance();
            c.setTime(startMonth);
            c.add(Calendar.MONTH, i);
            list.add(sdf.format(c.getTime()));
        }
        return list;
    }

    /**
     * 将日期字符串转化为日期。失败返回null。
     *
     * @param date     日期字符串
     * @param parttern 日期格式 如："YYYY-MM-dd"
     * @return 日期
     */
    public static Date stringToDate(String date, String parttern) {
        Date myDate = null;
        if (date != null) {
            try {
                myDate = new SimpleDateFormat(parttern).parse(date);
            } catch (Exception e) {
                return myDate;
            }
        }
        return myDate;
    }

    /**
     * 日期格式化(Date转换为String)
     *
     * @param date    日期
     * @param parttern 处理结果日期的显示格式，如："yyyy-MM-dd"
     * @return
     */
    public static String dateString(Date date, String parttern) {
        String dateString = "";
        if (date != null) {
            SimpleDateFormat formatter = new SimpleDateFormat(parttern);
            dateString = formatter.format(date);
        }
        return dateString;
    }

    // 获取当天的开始时间
    public static Date getDayBegin() {
        Calendar cal = new GregorianCalendar();
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);
        return cal.getTime();
    }

    // 获取当天的结束时间
    public static Date getDayEnd() {
        Calendar cal = new GregorianCalendar();
        cal.set(Calendar.HOUR_OF_DAY, 23);
        cal.set(Calendar.MINUTE, 59);
        cal.set(Calendar.SECOND, 59);
        return cal.getTime();
    }

    // 获取昨天的开始时间
    public static Date getBeginDayOfYesterday() {
        Calendar cal = new GregorianCalendar();
        cal.setTime(getDayBegin());
        cal.add(Calendar.DAY_OF_MONTH, -1);
        return cal.getTime();
    }

    // 获取昨天的结束时间
    public static Date getEndDayOfYesterDay() {
        Calendar cal = new GregorianCalendar();
        cal.setTime(getDayEnd());
        cal.add(Calendar.DAY_OF_MONTH, -1);
        return cal.getTime();
    }

    // 获取明天的开始时间
    public static Date getBeginDayOfTomorrow() {
        Calendar cal = new GregorianCalendar();
        cal.setTime(getDayBegin());
        cal.add(Calendar.DAY_OF_MONTH, 1);
        return cal.getTime();
    }

    // 获取明天的结束时间
    public static Date getEndDayOfTomorrow() {
        Calendar cal = new GregorianCalendar();
        cal.setTime(getDayEnd());
        cal.add(Calendar.DAY_OF_MONTH, 1);
        return cal.getTime();
    }

    // 获取上周的开始时间
    @SuppressWarnings("unused")
    public static Date getBeginDayOfLastWeek() {
        Date date = new Date();
        if (date == null) {
            return null;
        }
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        int dayofweek = cal.get(Calendar.DAY_OF_WEEK);
        if (dayofweek == 1) {
            dayofweek += 7;
        }
        cal.add(Calendar.DATE, 2 - dayofweek - 7);
        return getDayStartTime(cal.getTime());
    }

    // 获取上周的结束时间
    public static Date getEndDayOfLastWeek() {
        Calendar cal = Calendar.getInstance();
        cal.setTime(getBeginDayOfLastWeek());
        cal.add(Calendar.DAY_OF_WEEK, 6);
        Date weekEndSta = cal.getTime();
        return getDayEndTime(weekEndSta);
    }

    // 获取本月的开始时间
    public static Date getBeginDayOfMonth() {
        Calendar calendar = Calendar.getInstance();
        calendar.set(getNowYear(), getNowMonth() - 1, 1);
        return getDayStartTime(calendar.getTime());
    }

    // 获取本月的结束时间
    public static Date getEndDayOfMonth() {
        Calendar calendar = Calendar.getInstance();
        calendar.set(getNowYear(), getNowMonth() - 1, 1);
        int day = calendar.getActualMaximum(5);
        calendar.set(getNowYear(), getNowMonth() - 1, day);
        return getDayEndTime(calendar.getTime());
    }

    // 获取上月的开始时间
    public static Date getBeginDayOfLastMonth() {
        Calendar calendar = Calendar.getInstance();
        calendar.set(getNowYear(), getNowMonth() - 2, 1);
        return getDayStartTime(calendar.getTime());
    }

    // 获取上月的结束时间
    public static Date getEndDayOfLastMonth() {
        Calendar calendar = Calendar.getInstance();
        calendar.set(getNowYear(), getNowMonth() - 2, 1);
        int day = calendar.getActualMaximum(5);
        calendar.set(getNowYear(), getNowMonth() - 2, day);
        return getDayEndTime(calendar.getTime());
    }

    // 获取本年的开始时间
    public static Date getBeginDayOfYear() {
        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.YEAR, getNowYear());
        cal.set(Calendar.MONTH, Calendar.JANUARY);
        cal.set(Calendar.DATE, 1);
        return getDayStartTime(cal.getTime());
    }

    // 获取本年的结束时间
    public static java.util.Date getEndDayOfYear() {
        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.YEAR, getNowYear());
        cal.set(Calendar.MONTH, Calendar.DECEMBER);
        cal.set(Calendar.DATE, 31);
        return getDayEndTime(cal.getTime());
    }

    // 获取某个日期的开始时间
    public static Timestamp getDayStartTime(Date d) {
        Calendar calendar = Calendar.getInstance();
        if (null != d)
            calendar.setTime(d);
        calendar.set(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH), 0,
                0, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return new Timestamp(calendar.getTimeInMillis());
    }

    // 获取某个日期的结束时间
    public static Timestamp getDayEndTime(Date d) {
        Calendar calendar = Calendar.getInstance();
        if (null != d)
            calendar.setTime(d);
        calendar.set(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH), 23,
                59, 59);
        calendar.set(Calendar.MILLISECOND, 999);
        return new Timestamp(calendar.getTimeInMillis());
    }

    public static Date getStartDayOfMonth(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        //设置为当月最后一天
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        return getDayStartTime(calendar.getTime());
    }

    //获取指定日期的月份结束时间
    public static Date getEndDayOfMonth(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        //设置为当月最后一天
        calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
        return getDayEndTime(calendar.getTime());
    }

    // 获取今年是哪一年
    public static Integer getNowYear() {
        Date date = new Date();
        GregorianCalendar gc = (GregorianCalendar) Calendar.getInstance();
        gc.setTime(date);
        return Integer.valueOf(gc.get(1));
    }

    // 获取本月是哪一月
    public static int getNowMonth() {
        Date date = new Date();
        GregorianCalendar gc = (GregorianCalendar) Calendar.getInstance();
        gc.setTime(date);
        return gc.get(2) + 1;
    }

    //两个日期相差的月份
    public static int getDiffMonths(Date beginDate, Date endDate) {
        if (beginDate == null || endDate == null) {
            throw new IllegalArgumentException("getDiffMonths param is null!");
        }
        Calendar start = Calendar.getInstance();
        Calendar end = Calendar.getInstance();
        start.setTime(beginDate);
        end.setTime(endDate);
        int result = end.get(Calendar.MONTH) - start.get(Calendar.MONTH);
        return result;
    }

    // 两个日期相减得到的天数
    public static int getDiffDays(Date beginDate, Date endDate) {
        if (beginDate == null || endDate == null) {
            throw new IllegalArgumentException("getDiffDays param is null!");
        }
        long diff = (endDate.getTime() - beginDate.getTime()) / (1000 * 60 * 60 * 24);
        int days = new Long(diff).intValue();
        return days;
    }

    // 两个日期相减得到的毫秒数
    public static long dateDiff(Date beginDate, Date endDate) {
        long date1ms = beginDate.getTime();
        long date2ms = endDate.getTime();
        return date2ms - date1ms;
    }

    // 获取两个日期中的最大日期
    public static Date max(Date beginDate, Date endDate) {
        if (beginDate == null) {
            return endDate;
        }
        if (endDate == null) {
            return beginDate;
        }
        if (beginDate.after(endDate)) {
            return beginDate;
        }
        return endDate;
    }

    // 获取两个日期中的最小日期
    public static Date min(Date beginDate, Date endDate) {
        if (beginDate == null) {
            return endDate;
        }
        if (endDate == null) {
            return beginDate;
        }
        if (beginDate.after(endDate)) {
            return endDate;
        }
        return beginDate;
    }

    // 返回某月该季度的第一个月
    public static Date getFirstSeasonDate(Date date) {
        final int[] SEASON = {1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4};
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        int sean = SEASON[cal.get(Calendar.MONTH)];
        cal.set(Calendar.MONTH, sean * 3 - 3);
        return cal.getTime();
    }

    // 返回某个日期下几天的日期
    public static Date getNextDay(Date date, int i) {
        Calendar cal = new GregorianCalendar();
        cal.setTime(date);
        cal.set(Calendar.DATE, cal.get(Calendar.DATE) + i);
        return cal.getTime();
    }

    // 返回某个日期前几天的日期
    public static Date getFrontDay(Date date, int i) {
        Calendar cal = new GregorianCalendar();
        cal.setTime(date);
        cal.set(Calendar.DATE, cal.get(Calendar.DATE) - i);
        return cal.getTime();
    }

    // 获取某年某月到某年某月按天的切片日期集合(间隔天数的集合)
    @SuppressWarnings({"rawtypes", "unchecked"})
    public static List getTimeList(int beginYear, int beginMonth, int endYear, int endMonth, int k) {
        List list = new ArrayList();
        if (beginYear == endYear) {
            for (int j = beginMonth; j <= endMonth; j++) {
                list.add(getTimeList(beginYear, j, k));
            }
        } else {
            {
                for (int j = beginMonth; j < 12; j++) {
                    list.add(getTimeList(beginYear, j, k));
                }
                for (int i = beginYear + 1; i < endYear; i++) {
                    for (int j = 0; j < 12; j++) {
                        list.add(getTimeList(i, j, k));
                    }
                }
                for (int j = 0; j <= endMonth; j++) {
                    list.add(getTimeList(endYear, j, k));
                }
            }
        }
        return list;
    }

    // 获取某年某月按天切片日期集合(某个月间隔多少天的日期集合)
    @SuppressWarnings({"unchecked", "rawtypes"})
    public static List getTimeList(int beginYear, int beginMonth, int k) {
        List list = new ArrayList();
        Calendar begincal = new GregorianCalendar(beginYear, beginMonth, 1);
        int max = begincal.getActualMaximum(Calendar.DATE);
        for (int i = 1; i < max; i = i + k) {
            list.add(begincal.getTime());
            begincal.add(Calendar.DATE, k);
        }
        begincal = new GregorianCalendar(beginYear, beginMonth, max);
        list.add(begincal.getTime());
        return list;
    }

    /**
     * 指定日期新增天数
     *
     * @param date
     * @param day
     * @return
     */
    public static Date addDate(Date date, long day) {
        long time = date.getTime(); // 得到指定日期的毫秒数
        day = day * 24 * 60 * 60 * 1000; // 要加上的天数转换成毫秒数
        time += day; // 相加得到新的毫秒数
        return new Date(time); // 将毫秒数转换成日期
    }

    /**
     * 指定日期新增小时
     *
     * @param date
     * @param hour
     * @return
     */
    public static Date addHour(Date date, int hour) {
        if (date == null)
            return null;
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.add(Calendar.HOUR, hour);// 24小时制   
        date = cal.getTime();
        cal = null;
        return date;

    }

    /**
     * 指定日期新增年
     *
     * @param date
     * @param year
     * @return
     */
    public static Date addYear(Date date, int year) {
        if (date == null)
            return null;
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.add(Calendar.YEAR, year);// 年
        date = cal.getTime();
        cal = null;
        return date;

    }

    /**
     * 指定日期新增月
     *
     * @param date
     * @param year
     * @return
     */
    public static Date addMonth(Date date, int month) {
        if (date == null)
            return null;
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.add(Calendar.MONTH, month);// 月
        date = cal.getTime();
        cal = null;
        return date;

    }

    /**
     * @Description: 字符串转localdate 指定格式
     * @Param:
     */
    public static LocalDate stringToLocalDate(String date, String parttern) {
        LocalDate localDate = null;
        if (date != null) {
            try {
                localDate = LocalDate.parse(date, DateTimeFormatter.ofPattern(parttern));
            } catch (Exception e) {
                throw new IllegalArgumentException("日期格式错误，格式为" + parttern + "！");
            }
        }
        return localDate;
    }

    /**
     * @Description: 字符串转localdate
     * @Param:
     */
    public static LocalDate stringToLocalDate(String date) {
        LocalDate localDate = null;
        if (date != null) {
            try {
                localDate = LocalDate.parse(date);
            } catch (Exception e) {
                throw new IllegalArgumentException("日期格式错误！");
            }
        }
        return localDate;
    }

    /**
     * @Description: 字符串转 LocalDateTime 格式 yyyy-MM-dd HH:mm:ss
     * @Param [dateTime]
     */
    public static LocalDateTime stringToLocalDateTime(String dateTime) {
        LocalDateTime localDateTime = null;
        if (dateTime != null) {
            try {
                DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                localDateTime = LocalDateTime.parse(dateTime,df);
            } catch (Exception e) {
                throw new IllegalArgumentException("日期格式错误！");
            }
        }
        return localDateTime;
    }

    /**
     * @Description: LocalDateTime 转字符串 格式 yyyy-MM-dd HH:mm:ss
     * @Param [localDateTime]
     */
    public static String localDateTimeToString(LocalDateTime localDateTime) {
        String dateTime = null;
        if (localDateTime != null) {
            try {
                DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                dateTime = df.format(localDateTime);
            } catch (Exception e) {
                throw new IllegalArgumentException("日期格式错误！");
            }
        }
        return dateTime;
    }

    /**
     * @Description: LocalTime 转字符串 格式 HH:mm:ss
     * @Param [localTime]
     */
    public static String localTimeToString(LocalTime localTime) {
        String dateTime = null;
        if (localTime != null) {
            try {
                DateTimeFormatter df = DateTimeFormatter.ofPattern("HH:mm:ss");
                dateTime = df.format(localTime);
            } catch (Exception e) {
                throw new IllegalArgumentException("日期格式错误！");
            }
        }
        return dateTime;
    }

    /**
     * @Description: String 转LocalTime 格式 HH:mm:ss
     * @Param [localTime]
     */
    public static LocalTime stringToLocalTime(String time) {
        LocalTime dateTime = null;
        if (time != null) {
            try {
                DateTimeFormatter df = DateTimeFormatter.ofPattern("HH:mm:ss");
                dateTime = LocalTime.parse(time, df);
            } catch (Exception e) {
                throw new IllegalArgumentException("日期格式错误！");
            }
        }
        return dateTime;
    }

    /**
     * @Description: 获取两个日期之间的日期列表
     * @Param [startDay, endDay]
     */
    public static List<String> getBetweenDay(LocalDate startDay, LocalDate endDay) {
        List<String> list = new ArrayList();
        DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        long days = endDay.toEpochDay() - startDay.toEpochDay();
        for (int i = 0; i <= days; ++i) {
            list.add(df.format(startDay.plusDays(i)));
        }
        return list;
    }

    /**
     * @Description: LocalDateTime 转化为DatePowerInterceptor.java
     * @Param [ldt]
     */
    public static Date fromLocalDateTime(LocalDateTime ldt){
        ZoneId zoneId = ZoneId.systemDefault();
        ZonedDateTime zdt = ldt.atZone(zoneId);
        Date date = Date.from(zdt.toInstant());
        return date ;
    }

    /**
     * 日期在该月为第几周
     * @param str
     * @return
     * @throws Exception
     */
    public static int getWeek(String str) throws Exception {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Date date = sdf.parse(str);
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        //第几周
        int week = calendar.get(Calendar.WEEK_OF_MONTH);
        return week;
    }

    /**
     * 某年某月有多少天
     * @param year
     * @param month
     * @return
     */
    public static int getDaysByYearMonth(int year, int month) {
        Calendar a = Calendar.getInstance();
        a.set(Calendar.YEAR, year);
        a.set(Calendar.MONTH, month - 1);
        a.set(Calendar.DATE, 1);
        a.roll(Calendar.DATE, -1);
        int maxDate = a.get(Calendar.DATE);
        return maxDate;
    }

    /**
     * 获取该月 每周的起始日期和结束日期
     * @param date
     * @return
     */
    public static  List<String> getLastDayForWeekly(LocalDate date) {
        LocalDate firstDay = date.with(TemporalAdjusters.firstDayOfMonth());
        LocalDate lastDay = date.with(TemporalAdjusters.lastDayOfMonth());
        ArrayList list;
        for(list = new ArrayList(); firstDay.isBefore(lastDay); firstDay = firstDay.plusDays(1L)) {
            StringBuilder strbur = new StringBuilder();
            strbur.append(firstDay.toString());
            firstDay = firstDay.plusDays(6L);
            if (firstDay.isBefore(lastDay)) {
                strbur.append(",").append(firstDay.toString());
            } else {
                strbur.append(",").append(lastDay.toString());
            }
            list.add(strbur.toString());
        }
        return list;
    }

    /**
     * @Description: date 转datetime
     * @Param [date]
     */
    public static LocalDateTime date2LocalDateTime(Date date){
        Instant instant = date.toInstant();
        ZoneId zoneId = ZoneId.systemDefault();
        LocalDateTime localDateTime = instant.atZone(zoneId).toLocalDateTime();
        return localDateTime;
    }

    public static LocalDate date2LocalDate(Date date){
        LocalDate localDate = date.toInstant().atZone(ZoneOffset.ofHours(8)).toLocalDate();
        return localDate;
    }


}
